Linux環境でシェルスクリプト実行時に「No such file or directory」と出て、困ったことありませんか?
タイトルにある通りですが、皆さんはLinux環境でシェルスクリプト実行時に「No such file or directory」と出て、困ったことありませんか?
エラー文を見る限り、ファイルが存在しないという風に読めるが、確かに存在しているシェルスクリプトを実行しているはず。。。
そんな感じで困ったことが過去の案件でありました。
結論
色々考えられる原因はあるかと思います。
例えば、以下の通りです。
- 実は、タイポで存在しないファイルを実行していた
- ファイルのパスが間違えていた
- 文字コードがUTF-8以外だった
しかし、Gitを利用している場合は、まず改行コードを疑った方がいいです。
(この点は後述します。)
改行コードがCRLFとなっているシェルスクリプトをLinux環境で実行していた、というのが大半のケースだと思います。
OSによって採用されている改行コードが異なります。
- Linux: LF
- Windows: CRLF
そのため、標準ではない改行コードが入ったファイルを実行する際に不具合が発生しやすいです。
対処方法としましては、以下の通りです。
- Linux環境でsedコマンドで改行コードを置換する(CRLF→LF)
- Windows環境でvscodeなどのエディタで改行コードを変換・保存し、改めてLinux環境に運ぶ[1]
実例
実際私が過去の案件でこのエラーに遭遇した環境は、以下の通りです。
- OS: Amazon Linux2023
- シェルスクリプト:Bashスクリプト
今回は、Amazon Linux2023環境ではなく、MacOS(Sonoma 14.5)で再現させていただきます。
その点、ご了承ください。
簡単なシェルスクリプトを用意しました。
#!/bin/bash
echo "test"
echo "test2"
最初は改行コードをLFにしています。
この状態でシェルスクリプトを実行すると、うまくいきます。
$ ./test.sh
test
test2
次に、このシェルスクリプトをCRLFで保存します。
再度シェルスクリプトを実行すると、「No such file or directory」エラーが発生します。
$ ./test.sh
-bash: ./test.sh: /bin/bash^M: bad interpreter: No such file or directory
ちなみにzshでも同様の結果となりました。
#!/bin/zsh
echo "test"
echo "test2"
% ./test.sh
zsh: ./test.sh: bad interpreter: /bin/zsh^M: no such file or directory
そもそも何で改行コードが混ざっちゃうのか
これもあるあるだと思うのですが、
Gitの自動改行コード変換が原因です。
Gitの設定であるcore.autocrlfがデフォルトでtrueであり、
チェックアウトした際に改行コードがLFからCRLFに変換されます。
(コミットの際はCRLFからLFに変換されます。)
改行コードがCRLFになっている状態でファイルをWindows環境からLinux環境に運んでしまい、エラーに見舞われるという流れです。
core.autocrlfをtrueにするのか、falseにするのか、はたまたinputにするのかは色々と言われていますが、
そもそもの根本的な原因はWindows上のファイルを直接Linux環境に運ぶことだと思います。
どう対処すればいいか
このエラーが発生した案件がセキュリティ要件によって少々特殊な対応をとっており、
「デプロイ資材をWindowsのローカル端末からS3にアップロードし、Linuxの運用サーバからS3上にあるデプロイ資材をダウンロードする」という資材運搬をとっておりました。
このような運搬方法を取らずに、例えばLinuxの運用サーバからgit pullなどすれば、この問題は避けられていたと思います。
(もっと言えばGitHub Actionsなど使ってCI/CD環境を構築したかった。)
余程特殊な要件がない限り、Windows上のファイルを直接Linux環境に運ぶことは避けた方が無難です。
もしWindows上のファイルを直接Linux環境に運ぶ機会がある場合は、以下の対応などを検討してください。
- gitで管理していた場合「core.autocrlf」の設定をどうするのか、チーム内で検討する
- 意図しない改行コードの変更を防ぐために、ファイル転送を行うツールではバイナリモードに設定する
最後に
前職での経験を元に小ネタとしてまとめました。
お役に立てたのなら幸いです。
ここでいう「運ぶ」とは、WinSCPやTerratermなどツールでファイル転送したり、S3などのストレージ経由でファイルを転送したりすることを指します。 ↩︎